package org.moonshiner.controller.web;

import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.http.HttpServletRequest;

import org.moonshiner.controller.svn.SVNRepositoryProvider;
import org.moonshiner.model.constants.ErrorCode;
import org.moonshiner.model.constants.ErrorMessages;
import org.moonshiner.model.context.AppContext;
import org.moonshiner.model.user.SvnUserCredentials;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.support.SessionStatus;
import org.tmatesoft.svn.core.SVNAuthenticationException;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.auth.ISVNAuthenticationManager;
import org.tmatesoft.svn.core.internal.wc.DefaultSVNAuthenticationManager;
import org.tmatesoft.svn.core.io.SVNRepository;
import org.tmatesoft.svn.core.wc.SVNWCUtil;

@Controller
@RequestMapping(value = "/svn")
public class LoginSVNController {

	public static final String SVN_URL_PARAMETER_KEY = "svnUrl";

	@RequestMapping(value = "/login", method = RequestMethod.GET)
	public String prepareLoginForm() {

		return "redirect:/";
	}

	@RequestMapping(value = "/login", method = RequestMethod.POST)
	public String login(
			@ModelAttribute("userCredentials") SvnUserCredentials userCredentials,
			BindingResult result, SessionStatus status) {

		List<String> errors= new ArrayList<String>();
		
		ISVNAuthenticationManager authenticationManager = createAuthManager(userCredentials);

		SVNRepository repository = ((SVNRepositoryProvider) AppContext
				.getAppContext().getBean(SVNRepositoryProvider.BEAN_NAME))
				.getRepository();
		repository.setAuthenticationManager(authenticationManager);
		
		try {
			repository.testConnection();
		} catch (SVNAuthenticationException e) {
			errors.add(ErrorMessages.INVALID_USER_CREDENTIALS);
		} catch (SVNException e) {
			e.printStackTrace();
		}

		return "svn/repoBrowser";
	}

	@RequestMapping(value = "/checkUrl", method = RequestMethod.POST)
	public String checkSvnUrl(HttpServletRequest request, ModelMap model) {

		List<String> errors = new ArrayList<String>();
		String result = "";
		SVNRepository repository = null;
		String svnUrl = request.getParameter(SVN_URL_PARAMETER_KEY);
		try {
			repository = ((SVNRepositoryProvider) AppContext.getAppContext()
					.getBean(SVNRepositoryProvider.BEAN_NAME))
					.initRepository(svnUrl);
		} catch (SVNException e) {
			if (e.getMessage().contains(ErrorCode.MALFORMED_URL)) {
				errors.add(ErrorMessages.MALFORMED_URL);
			}
		}

		if (!isHostAvaliable(repository)) {
			errors.add(ErrorMessages.HOST_IS_UNAVALIABLE);
		}

		model.addAttribute("errors", errors);
		if (errors.isEmpty()) {
			model.addAttribute(SvnUserCredentials.ATTRIBUTE_NAME,
					new SvnUserCredentials());
			result = "svn/loginForm";
		} else {
			result = "home";
		}
		return result;
	}

	private boolean isHostAvaliable(SVNRepository repository) {
		boolean result = true;

		if (repository == null) {
			return false;
		}

		try {
			repository.getRepositoryUUID(true);
		} catch (SVNException e) {
			if (e.getCause() != null
					&& e.getCause().getClass()
							.equals(UnknownHostException.class)) {
				result = false;
			}
		}

		return result;
	}

	private ISVNAuthenticationManager createAuthManager(
			SvnUserCredentials userCredentials) {
		ISVNAuthenticationManager authenticationManager = SVNWCUtil
				.createDefaultAuthenticationManager(
						userCredentials.getUserName(),
						userCredentials.getPassword());
		((DefaultSVNAuthenticationManager) authenticationManager)
				.setAuthenticationForced(true);
		return authenticationManager;
	}
}
